/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package infra;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.security.cert.X509Certificate;
import modelo.Comprovante;
import sun.misc.BASE64Encoder;

/**
 *
 * @author rmvanti
 */
public class UtilCertificados {

    private File repositorio;
    private KeyStore ks;
    private char[] senha;
    private BASE64Encoder encoder;
    private KeyPair parChave;

    public UtilCertificados() {
        this.encoder = new BASE64Encoder();
    }//fim construtor

    /**
     * Esse metodo busca no repositorio cujo nome é passado como parametro
     * a chave privada do certificado cujo nome é passado como parametro
     * @param nomecertificado 
     * @param senhaCertificado
     * @param nomeRepositorio
     * @param senhaRepositorio
     * @throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
     * @return PrivateKey
     */
    public PrivateKey getChavePrivada(String nomeCertificado, String senhaCertificado, String nomeRepositorio, String senhaRepositorio) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
        this.ks = KeyStore.getInstance("JKS");
        this.senha = senhaRepositorio.toCharArray();
        this.repositorio = new File(nomeRepositorio + ".jks");
        this.ks.load(new FileInputStream(this.repositorio), this.senha);
        this.parChave = getParChave(this.ks, nomeCertificado, senhaCertificado.toCharArray());
        return this.parChave.getPrivate();
    }
    
    /**
     * Esse metodo busca no repositorio cujo nome é passado como parametro
     * a chave publica do certificado cujo nome é passado como parametro
     * @param nomecertificado 
     * @param senhaCertificado
     * @param nomeRepositorio
     * @param senhaRepositorio
     * @throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
     * @return PublicKey
     */
    public PublicKey getChavePublica(String nomeCertificado, String senhaCertificado, String nomeRepositorio, String senhaRepositorio) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
        this.ks = KeyStore.getInstance("JKS");
        this.senha = senhaRepositorio.toCharArray();
        this.repositorio = new File(nomeRepositorio + ".jks");
        this.ks.load(new FileInputStream(this.repositorio), this.senha);
        this.parChave = getParChave(this.ks, nomeCertificado, senhaCertificado.toCharArray());
        return this.parChave.getPublic();
    }
    
    /**
     * Essa função pega o texto plano da chave privada passada como 
     * parametro 
     * @param chavePrivada
     * @return String
     */
    public String visualizarChavePrivada(PrivateKey chavePrivada){
        return this.encoder.encode(chavePrivada.getEncoded());
    }
    
    /**
     * Essa função pega o texto plano da chave publica passada como 
     * parametro 
     * @param chavePublica
     * @return String
     */
    public String visualizarChavePublica(PublicKey chavePublic){
        return this.encoder.encode(chavePublic.getEncoded());
    }

    /**
     * Essa função pega a chave publica em um arquivo .cer 
     * @param nomeCertificado nome do arquivo do certificado sem a extensão
     * @return PublicKey
     */
    public PublicKey getChavePublicaArquivoCer(String nomeCertificado) throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, javax.security.cert.CertificateException {
        FileInputStream arquivoCer = new FileInputStream(nomeCertificado+".cer");
        X509Certificate certificado = X509Certificate.getInstance(arquivoCer);
        return certificado.getPublicKey();
    }
    
    /**
     * Essa função retorna um par de chaves 
     * @param keystore repositorio de onde se quer buscar o certificado
     * @param alias nome do certificado do qual se quer o par de chaves
     * @param password senha do certificado
     */
    private KeyPair getParChave(KeyStore keystore, String alias, char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
        Key key = keystore.getKey(alias, password);
        if (key instanceof PrivateKey) {
            Certificate cert = keystore.getCertificate(alias);
            PublicKey publicKey = cert.getPublicKey();
            return new KeyPair(publicKey, (PrivateKey) key);
        }//fim if
        return null;
    }//fim getChavePrivada
    
    public String criptografarDocumento(String nomeCliente, String mensagem) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, NoSuchPaddingException, IllegalBlockSizeException, KeyStoreException, FileNotFoundException, IOException, CertificateException, UnrecoverableKeyException, javax.security.cert.CertificateException, BadPaddingException{
        String textoCifrado = "";
        Cipher cifra = Cipher.getInstance("RSA");  
        cifra.init(Cipher.ENCRYPT_MODE, getChavePublicaArquivoCer(nomeCliente));  
        byte[] mensagemCifrada = cifra.doFinal(mensagem.getBytes());  
        textoCifrado = new String(Base64.encode(mensagemCifrada));  
        return textoCifrado;
    }
    
    public String descriptografarDocmento(String nomeCliente, String mensagemCifrada) throws InvalidKeyException, KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
        Cipher cifra = Cipher.getInstance("RSA");  
        PrivateKey chavePrivada = getChavePrivada(nomeCliente, nomeCliente.toLowerCase(), "Cliente", "cliente");
        //Decifraria a mensagem se fivesse a chave privada neste ponto
        cifra.init(Cipher.DECRYPT_MODE, chavePrivada);  
        byte[] mensagemOriginal = cifra.doFinal(Base64.decode(mensagemCifrada));  
        return new String(mensagemOriginal);                         
    }
    
    /*METODO PARA TESTE*/
    /*
    public static void main(String[] args){
        UtilCertificados util = new UtilCertificados();
        try{
            //chave privada
            System.out.println("Inicio da chave privada:");
            System.out.println(util.getChavePrivada("rogerio", "rogerio", "Cliente", "cliente"));;
            System.out.println("Fim chave privada\n");
            
            //chave publica
            System.out.println("Inicio da chave public:");
            System.out.println(util.getChavePublicaArquivoCer("rogerio"));
            System.out.println("Fim chave publica\n");
            
            //chave privada
            System.out.println("Inicio da chave privada:");
            System.out.println(util.visualizarChavePrivada(util.getChavePrivada("rogerio", "rogerio", "Cliente", "cliente")));
            System.out.println("Fim chave privada\n");
            
            //chave publica
            System.out.println("Inicio da chave public:");
            System.out.println(util.visualizarChavePublica(util.getChavePublicaArquivoCer("rogerio")));
            System.out.println("Fim chave publica\n");
            
        }catch(KeyStoreException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(FileNotFoundException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(IOException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(NoSuchAlgorithmException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(CertificateException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(UnrecoverableKeyException erro){
            System.out.println("ERRO: " + erro.getMessage());
        }catch(javax.security.cert.CertificateException erro){
            System.out.println("ERRO: "+ erro.getMessage());
        }//fim catch
    }
    */
}//fim class
